

#include <string.h>			// memcpy
#include "debug.h"
#include "LPC23xx.h"
#include "usbapi.h"
#include "vcom.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "macros.h"
#include "fout.h"
#include "cmd.h"

//#include "cmd.h"

//#include "utils.h"
//#include "fifoBuf.h"
//#include "printf.h"

//#include "Application.h"
//#include "std_io.h"
//#include "ModuleDef.h"

xQueueHandle vcom_queue;

#define BAUD_RATE	115200

#define INT_IN_EP			0x81
#define BULK_OUT_EP		0x05
#define BULK_IN_EP		0x82

#define MAX_PACKET_SIZE	64

#define LE_WORD(x)		((x)&0xFF),((x)>>8)

// CDC definitions
#define CS_INTERFACE				0x24
#define CS_ENDPOINT				0x25

#define	SET_LINE_CODING			0x20
#define	GET_LINE_CODING			0x21
#define	SET_CONTROL_LINE_STATE	0x22

#define	INT_VECT_NUM	0

#define IRQ_MASK 0x00000080

// data structure for GET_LINE_CODING / SET_LINE_CODING class requests
typedef struct {
	unsigned long		dwDTERate;
	unsigned char		bCharFormat;
	unsigned char		bParityType;
	unsigned char		bDataBits;
} TLineCoding;

static TLineCoding LineCoding = {115200, 0, 0, 8};
static unsigned char abBulkBuf[64];
static unsigned char abClassReqData[8];
static volatile int fBulkInBusy;
static volatile int fChainDone;


static const unsigned char abDescriptors[] = {

// device descriptor
	0x12,
	DESC_DEVICE,
	LE_WORD(0x0101),			// bcdUSB
	0x02,						// bDeviceClass
	0x00,						// bDeviceSubClass
	0x00,						// bDeviceProtocol
	MAX_PACKET_SIZE0,			// bMaxPacketSize
	LE_WORD(0xFFFF),			// idVendor
	LE_WORD(0x0005),			// idProduct
	LE_WORD(0x0100),			// bcdDevice
	0x01,						// iManufacturer
	0x02,						// iProduct
	0x03,						// iSerialNumber
	0x01,						// bNumConfigurations

// configuration descriptor
	0x09,
	DESC_CONFIGURATION,
	LE_WORD(67),				// wTotalLength
	0x02,						// bNumInterfaces
	0x01,						// bConfigurationValue
	0x00,						// iConfiguration
	0xC0,						// bmAttributes
	0x32,						// bMaxPower
// control class interface
	0x09,
	DESC_INTERFACE,
	0x00,						// bInterfaceNumber
	0x00,						// bAlternateSetting
	0x01,						// bNumEndPoints
	0x02,						// bInterfaceClass
	0x02,						// bInterfaceSubClass
	0x01,						// bInterfaceProtocol, linux requires value of 1 for the cdc_acm module
	0x00,						// iInterface
// header functional descriptor
	0x05,
	CS_INTERFACE,
	0x00,
	LE_WORD(0x0110),
// call management functional descriptor
	0x05,
	CS_INTERFACE,
	0x01,
	0x01,						// bmCapabilities = device handles call management
	0x01,						// bDataInterface
// ACM functional descriptor
	0x04,
	CS_INTERFACE,
	0x02,
	0x02,						// bmCapabilities
// union functional descriptor
	0x05,
	CS_INTERFACE,
	0x06,
	0x00,						// bMasterInterface
	0x01,						// bSlaveInterface0
// notification EP
	0x07,
	DESC_ENDPOINT,
	INT_IN_EP,					// bEndpointAddress
	0x03,						// bmAttributes = intr
	LE_WORD(8),					// wMaxPacketSize
	0x0A,						// bInterval
// data class interface descriptor
	0x09,
	DESC_INTERFACE,
	0x01,						// bInterfaceNumber
	0x00,						// bAlternateSetting
	0x02,						// bNumEndPoints
	0x0A,						// bInterfaceClass = data
	0x00,						// bInterfaceSubClass
	0x00,						// bInterfaceProtocol
	0x00,						// iInterface
// data EP OUT
	0x07,
	DESC_ENDPOINT,
	BULK_OUT_EP,				// bEndpointAddress
	0x02,						// bmAttributes = bulk
	LE_WORD(MAX_PACKET_SIZE),	// wMaxPacketSize
	0x00,						// bInterval
// data EP in
	0x07,
	DESC_ENDPOINT,
	BULK_IN_EP,					// bEndpointAddress
	0x02,						// bmAttributes = bulk
	LE_WORD(MAX_PACKET_SIZE),	// wMaxPacketSize
	0x00,						// bInterval
	
	// string descriptors
	0x04,
	DESC_STRING,
	LE_WORD(0x0409),

	0x0E,
	DESC_STRING,
	'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,

	0x14,
	DESC_STRING,
	'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,

	0x12,
	DESC_STRING,
	'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,

// terminating zero
	0
}; 

//#define   VCOM_TXD_BUF_SIZE		(64*4)

//char vcom_txd_buf[VCOM_TXD_BUF_SIZE];

cmd_msg_t vcom_cmd = {FOUT_DEV_VCOM,""};
unsigned char vcom_pcmd = 0;

/**
	Local function to handle incoming bulk data
		
	@param [in] bEP
	@param [in] bEPStatus
 */
static void BulkOut(unsigned char bEP, unsigned char bEPStatus)
{
	unsigned char i = 0;
	// get data from USB into intermediate buffer
	unsigned char len = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf));

	for(i=0; len > 0; i++)
	{
		vcom_cmd.cmd_str[vcom_pcmd] = abBulkBuf[i];
		
		//	DBG("%c",vcom_cmd.cmd_str[vcom_pcmd]); //Dima

		if ( vcom_cmd.cmd_str[vcom_pcmd] == '\r' )  
		{
			vcom_cmd.cmd_str[vcom_pcmd] = 0;
			vcom_pcmd = 0;

			//	DBG(":%s",vcom_cmd.cmd_str); //Dima

			xQueueSend(cmd_queue, &vcom_cmd, portMAX_DELAY); //portMAX_DELAY
		}
		else
		{
			vcom_pcmd++;
			vcom_pcmd %= CMD_IN_BUFFER_SIZE-1;
		}

		len--;

	}
}


#define   VCOM_SEND_PACKET_SIZE	(MAX_PACKET_SIZE-1)

void vcom_putstr ( char* buf )
{
	if ( buf == NULL )
		return;
	
	int len = strlen(buf);

	while( len )
	{
		if ( len > VCOM_SEND_PACKET_SIZE )
		{
			memcpy(abBulkBuf,buf,VCOM_SEND_PACKET_SIZE);
			USBHwEPWrite(BULK_IN_EP, abBulkBuf, VCOM_SEND_PACKET_SIZE);
			len -= VCOM_SEND_PACKET_SIZE;
		}
		else
		{
			memcpy(abBulkBuf,buf,len);
			USBHwEPWrite(BULK_IN_EP, abBulkBuf, len);
			len = 0;
		}
	}
}


/**
	Local function to handle outgoing bulk data
		
	@param [in] bEP
	@param [in] bEPStatus
 */
static void BulkIn(unsigned char bEP, unsigned char bEPStatus)
{
	//DBG(""); //Dima
	//SendNextBulkIn(bEP, FALSE);
}


/**
	Local function to handle the USB-CDC class requests
		
	@param [in] pSetup
	@param [out] piLen
	@param [out] ppbData
 */
static int HandleClassRequest(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData)
{
	switch (pSetup->bRequest) {

		// set line coding
		case SET_LINE_CODING:
			DBG("SET_LINE_CODING\n");
			memcpy((unsigned char *)&LineCoding, *ppbData, 7);
			//MemCpy(&LineCoding, *ppbData, 7);
			*piLen = 7;
			DBG("dwDTERate=%u, bCharFormat=%u, bParityType=%u, bDataBits=%u\n",
				 (unsigned int)LineCoding.dwDTERate,
				 LineCoding.bCharFormat,
				 LineCoding.bParityType,
				 LineCoding.bDataBits);
			break;

			// get line coding
		case GET_LINE_CODING:
//			DBG("GET_LINE_CODING\n");
			*ppbData = (unsigned char *)&LineCoding;
			*piLen = 7;
			break;

			// set control line state
		case SET_CONTROL_LINE_STATE:
			// bit0 = DTR, bit = RTS
//			DBG("SET_CONTROL_LINE_STATE %X\n", pSetup->wValue);
			break;

		default:
			return FALSE;
	}
	return TRUE;
}


/**
	USB device status handler
	
	Resets state machine when a USB reset is received.
 */
static void USBDevIntHandler(unsigned char bDevStatus)
{
	if ((bDevStatus & DEV_STATUS_RESET) != 0) 
	{
		fBulkInBusy = FALSE;
	}
}
 
void vcom_connect ( int con )
{
	USBHwConnect(con);
}

/*************************************************************************
	main
	====
**************************************************************************/
void vcom_init(void)
{
//	int i;
	// initialise stack
	USBInit();

	// register descriptors
	USBRegisterDescriptors(abDescriptors);

	// register class request handler
	USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);

	// register endpoint handlers
	USBHwRegisterEPIntHandler(INT_IN_EP, NULL);
	//Dima USBHwRegisterEPIntHandler(BULK_IN_EP, BulkIn);
	USBHwRegisterEPIntHandler(BULK_OUT_EP, BulkOut);
	
	// register frame handler
	//USBHwRegisterFrameHandler(USBFrameHandler);	// Dima
	//USBHwRegisterFrameHandler(NULL);
	
	// register device event handler
	USBHwRegisterDevIntHandler(USBDevIntHandler);		// Dima
	
	// initialise VCOM
	
	//DBG("Starting USB communication\n");
	VICVectCntl22 = 0x01;
  //VICVectAddr22 = (unsigned int)USBIntHandler;
	VICVectAddr22 = (unsigned int)USBHwISR;
  
	// set up USB interrupt
	VICIntSelect &= ~(1UL<<22);               // select IRQ for USB
	VICIntEnable |= (1UL<<22);
	
	//VCOM_init();
	fBulkInBusy = FALSE;
	fChainDone = TRUE;


	// connect to bus
	USBHwConnect(TRUE);
}

